/********************************************************/
/*	Author:		gong_libin			*/
/*	Date:		2014_08_08			*/
/*	File:		GtRmUtil.c			*/
/********************************************************/

#include "GtRmUtil.h"

int GtRuRawInitRecv(char* pszEth)
{
	int iSize = GT_RU_BUF;
	int iSocket = GT_FAILURE;
	struct ifreq stIfreq;
	struct sockaddr_ll stAddr;

	if (GT_FAILURE != (iSocket = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL)))) {
		if (GT_SUCCESS == setsockopt(iSocket, SOL_SOCKET, SO_RCVBUF, &iSize, sizeof(iSize))) {
			strcpy(stIfreq.ifr_name, pszEth);
			if (GT_SUCCESS == ioctl(iSocket, SIOCGIFINDEX, &stIfreq)) {
				stAddr.sll_family = PF_PACKET;
				stAddr.sll_protocol = htons(ETH_P_ALL);
				stAddr.sll_ifindex = stIfreq.ifr_ifindex;
				if (GT_SUCCESS != bind(iSocket, (struct sockaddr*)&stAddr, sizeof(stAddr))) {
					goto GtError;
				}
			}
			else {
				goto GtError;
			}
		}
		else {
			goto GtError;
		}
	}

	return iSocket;

GtError:
	GT_ERROR("%s\n", strerror(errno));
	close(iSocket);

	return GT_FAILURE;
}

int GtRuRawInitSend(char* pszAddr)
{
	int iHead = 1;
	int iSize = GT_RU_BUF;
	int iSocket = GT_FAILURE;
	struct sockaddr_in stAddr;

	if (GT_FAILURE != (iSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW))) {
		if (GT_FAILURE != setsockopt(iSocket, IPPROTO_IP, IP_HDRINCL, &iHead, sizeof(iHead))) {
			if (GT_FAILURE != setsockopt(iSocket, SOL_SOCKET, SO_SNDBUF, &iSize, sizeof(iSize))) {
				if (GT_FAILURE != fcntl(iSocket, F_SETFL, fcntl(iSocket, F_GETFL, 0) | O_NONBLOCK)) {
					stAddr.sin_family = AF_INET;
					stAddr.sin_port = htons(INADDR_ANY);
					stAddr.sin_addr.s_addr = inet_addr(pszAddr);
					if (GT_FAILURE == bind(iSocket, (struct sockaddr*)&stAddr, sizeof(stAddr))) {
						goto GtError;
					}
				}
				else {
					goto GtError;
				}
			}
			else {
				goto GtError;
			}
		}
		else {
			goto GtError;
		}
	}
	else {
		goto GtError;
	}

	return iSocket;

GtError:
	GT_ERROR("%s\n", strerror(errno));
	close(iSocket);

	return GT_FAILURE;
}

int GtRuConfigure(char* pszConf, char* pszBlock, GTRUCONF_S* pstConf)
{
	FILE* pstFile = NULL;
	int iFlag = GT_FAILURE;
	int iReturn = GT_SUCCESS;
	char szLine[GT_BYTE128] = { 0 };

	if (NULL != (pstFile = fopen(pszConf, "r"))) {
		while (NULL != fgets(szLine, GT_BYTE128, pstFile)) {
			GtRuTrimLeft(szLine);
			if ('#' != szLine[0]) {
				GtRuTrimRight(szLine);
				if (GT_SUCCESS == iFlag) {
					if ('[' != szLine[0]) {
						if (GT_SUCCESS != (iReturn = GtRuKeyValue(szLine, pstConf))) {
							break;
						}
					}
					else {
						break;
					}
				}
				else {
					if (GT_SUCCESS == strncasecmp(&szLine[1], pszBlock, strlen(pszBlock))) {
						iFlag = GT_SUCCESS;
					}
				}
			}
			memset(szLine, '\0', GT_BYTE128);
		}
		fclose(pstFile);
	}
	else {
		GT_ERROR("%s\n", strerror(errno));
		iReturn = GT_FAILURE;
	}

	return iReturn;
}

void GtRuConfPrint(char* pszBlock, GTRUCONF_S* pstConf)
{
	GT_PRINT("[%s]\n", pszBlock);
	GT_PRINT("Port: %s\n", pstConf->m_szPort);
	GT_PRINT("Total: %d\n", pstConf->m_uiDevice);
	GT_PRINT("%s = %s\n", GT_RU_ETH, pstConf->m_szEther);

	return;
}

void GtRuTrimAll(char* pszLine)
{
	GtRuTrimLeft(pszLine);
	GtRuTrimRight(pszLine);

	return;
}

void GtRuTrimLeft(char* pszLine)
{
	char* pszCur = pszLine;

	while ('\t' == *pszCur || '\r' == *pszCur || '\n' == *pszCur || ' ' == *pszCur) pszCur += 1;
	if (pszCur != pszLine)  while ('\0' != (*pszLine ++ = *pszCur ++)) {}

	return;
}

void GtRuTrimRight(char* pszLine)
{
	char* pszCur = pszLine;

	if (strlen(pszLine) > 0) {
		while ('\0' != *pszCur && '#' != *pszCur) pszCur += 1;
		*pszCur -- = '\0';
		while ('\t' == *pszCur || '\r' == *pszCur || '\n' == *pszCur || ' ' == *pszCur) pszCur -= 1;
		*(pszCur + 1) = '\0';
	}

	return;
}

int GtRuKeyValue(char* pszLine, GTRUCONF_S* pstConf)
{
	char* pszCur = pszLine;
	int iReturn = GT_SUCCESS;
	int iLength = strlen(pszLine);

	while (pszCur - pszLine < iLength && '=' != *pszCur) pszCur += 1;

	if (pszCur - pszLine != iLength) {
		*pszCur ++ = '\0';
		GtRuTrimLeft(pszCur);
		GtRuTrimRight(pszLine);
		if (GT_SUCCESS == strncmp(pszLine, GT_RU_POT, strlen(GT_RU_POT))) {
			strncpy(pstConf->m_szPort, pszCur, GT_BYTE128);
		}
		else if (GT_SUCCESS == strncmp(pszLine, GT_RU_ETH, strlen(GT_RU_ETH))) {
			strncpy(pstConf->m_szEther, pszCur, GT_BYTE128);
		}
		else {
			if (0 != isdigit(pszCur[0])) {
				iReturn = GtRuAddrIn(pszCur, pstConf);
			}
			else {
				iReturn = GtRuAddrUn(pszCur, pstConf);
			}
		}
	}

	return iReturn;
}

void* GtRuShmCreat(int iReset)
{
	int iShm = 0;
	void* pReturn = NULL;

	if (GT_FAILURE != (iShm = shmget(ftok(GT_RU_PATH, GT_RU_KEY), sizeof(GTRUSHM_S) * GT_RU_TTL, IPC_CREAT | 0777))) {
		if (NULL != (pReturn = shmat(iShm, NULL, 0))) {
			if (0 != iReset) {
				memset(pReturn, '\0', sizeof(GTRUSHM_S) * GT_RU_TTL);
			}
		}
		else {
			GT_ERROR("%s\n", strerror(errno));
			shmctl(iShm, IPC_RMID, 0);
		}
	}
	else {
		GT_ERROR("%s\n", strerror(errno));
	}

	return pReturn;
}

int GtRuAddrIn(char* pszLine, GTRUCONF_S* pstConf)
{
	char* pszAddr = NULL;
	int iReturn = GT_SUCCESS;

	if (NULL != (pszAddr = strchr(pszLine, '|'))) {
		*pszAddr ++ = '\0';
		if (GT_FAILURE != (GT_RU_ADSC = GtRuRawInitSend(pszLine))) {
			GT_RU_ADIN.sin_family = AF_INET;
			GT_RU_ADIN.sin_addr.s_addr = inet_addr(pszAddr);
			GT_RU_ADIN.sin_port = htons(atoi(pstConf->m_szPort));
			GT_RU_ADSZ = sizeof(struct sockaddr_in);
			pstConf->m_uiDevice += 1;
		}
		else {
			GT_ERROR("Failed to GtRuRawInitSend\n");
			iReturn = GT_FAILURE;
		}
	}
	else {
		GT_ERROR("Failed to get addr\n");
		iReturn = GT_FAILURE;
	}

	return iReturn;
}

int GtRuAddrUn(char* pszLine, GTRUCONF_S* pstConf)
{
	int iSize = GT_RU_BUF;
	int iReturn = GT_SUCCESS;

	if (GT_FAILURE != (GT_RU_ADSC = socket(AF_UNIX, SOCK_DGRAM, 0))) {
		if (GT_FAILURE != setsockopt(GT_RU_ADSC, SOL_SOCKET, SO_SNDBUF, &iSize, sizeof(iSize))) {
			GT_RU_ADUN.sun_family = AF_UNIX;
			GT_RU_ADSZ = sizeof(struct sockaddr_un);
			memcpy(GT_RU_ADUN.sun_path, pszLine, strlen(pszLine));
			if (GT_SUCCESS != (iReturn = connect(GT_RU_ADSC, GT_RU_ADAD, GT_RU_ADSZ))) {
				GT_ERROR("%s\n", strerror(errno));
				iReturn = GT_FAILURE;
				close(GT_RU_ADSC);
			}
			else {
				pstConf->m_uiDevice += 1;
			}
		}
		else {
			GT_ERROR("%s\n", strerror(errno));
			iReturn = GT_FAILURE;
			close(GT_RU_ADSC);
		}
	}
	else {
		GT_ERROR("%s\n", strerror(errno));
		iReturn = GT_FAILURE;
	}

	return iReturn;
}

void* GtRuMalloc(UINT uiSize)
{
	void* pReturn = NULL;

	if (NULL != (pReturn = malloc(sizeof(UCHAR) * uiSize))) {
		memset(pReturn, '\0', sizeof(UCHAR) * uiSize);
	}
	else {
		GT_ERROR("%s\n", strerror(errno));
	}

	return pReturn;
}

void GtRuFree(void** ppFree)
{
	if (NULL != *ppFree) {
		free(*ppFree);
		*ppFree = NULL;
	}

	return;
}

void GtRuTimer(struct timeval* pstOn, struct timeval* pstOff, char* pszTime)
{
	if (pstOff->tv_usec == pstOn->tv_usec) {
		sprintf(pszTime, "%ld second 0 microsecond", pstOff->tv_sec - pstOn->tv_sec);
	}
	else if (pstOff->tv_usec > pstOn->tv_usec) {
		sprintf(pszTime, "%ld second %ld microsecond", pstOff->tv_sec - pstOn->tv_sec, pstOff->tv_usec - pstOn->tv_usec);
	}
	else {
		sprintf(pszTime, "%ld second %ld microsecond", pstOff->tv_sec - pstOn->tv_sec - 1, 1000000L - pstOn->tv_usec + pstOff->tv_usec);
	}

	return;
}
